<?php

namespace App\Common;

/**
 * 常用方法和判断方式
 * Class Checking
 * @package app\common\controller
 */
class Checking
{
    /**
     * 方法对应的错误信息
     */
    const MESSAGE = [
        'default' => 'ok',
        'checkPassword' => '密码有误',
        'passwordRule' => '密码格式有误',
        'phoneRule' => '手机号有误',
        'phoneIsMysql' => '手机号有误或者此手机号已存在',
        'keyIsExistence' => '参数不准为空',
        'transactionPwdRule' => '请输入6位数纯数字',
        'checkIdCard' => '身份证不符合格式',
        'bankCardRule' => '银行卡不符合格式'
    ];

    /**
     * 密码hash加密，加密方式默认为PASSWORD_DEFAULT
     * @param string $password
     */
    public static function passwordHash( $password = '' )
    {
        return password_hash( $password, PASSWORD_DEFAULT );
    }

    /**
     * 验证password_hash生成的密码
     * @param $hashPassword
     * @param $password
     * @return bool
     */
    public static function checkPassword( $hashPassword, $password )
    {
        return password_verify( $password, $hashPassword );
    }

    /**
     * 密码长度，组合判断
     * @param string $str
     * @return bool
     */
    public static function passwordRule( $str = '' )
    {
        if ( preg_match( "/^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{6,20}$/", $str ) ) {
            return true;
        }
        return false;
    }

    /**
     * 判断交易密码是否为纯数字并且长度为六位
     * @param $password
     * @param $len
     * @return bool
     */
    public static function transactionPwdRule( $password, $len = 6 )
    {
        if ( preg_match( "/^\d*$/", $password ) && strlen( $password ) == $len ) {
            return true;
        }
        return false;
    }

    /**
     * 判断是否存在此用户
     */
    public static function is_user( $uid )
    {
        $res = db( 'users' )->where( ['id' => $uid] )->find();
        if ( $res ) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 传入处理字符串方法，处理字符串
     * @param $str
     * @param string $filter
     * @return mixed
     */
    public static function filterString( $str, $filter = 'strip_tags,htmlspecialchars' )
    {
        if ( !is_array( $filter ) ) {
            $filter = array_filter( explode( ",", $filter ) );
        }

        foreach ( $filter as $k => $v ) {
            $str = $v( $str );
        }
        return $str;
    }


    /**
     * 判断手机号格式
     * @param $phone
     * @return bool
     */
    public static function phoneRule( $phone )
    {
        if ( preg_match( "/^1[3456789]\d{9}$/", $phone ) ) {
            return true;
        }
        return false;
    }

    /**
     * 判断手机号是否存在某个表中
     * @param $phone 手机号
     * @param $model 表模型 object
     * @param $field 数据表字段
     */
    public static function phoneIsMysql( $phone, $tableName, $model, $field = 'phone' )
    {
        return $model->where( $field, $phone )->has( $tableName );

    }

    /**
     * 处理二位数组，使用字段作为元素的下表
     * @param $arr 要处理的数组
     * @param $field    要作为数组索引的数组字段,支持多个字段,逗号分隔: ',id,name,'
     */
    public static function arrayFieldForKey( $arr = [], $field = '' )
    {
        if ( empty( $arr ) || empty( $field ) ) {
            return [];
        }
        $returnData = [];
        foreach ( $arr as $k => $v ) {
            if ( false !== strstr( $field, ',' ) ) {
                $strs = array_values( array_filter( explode( ',', $field ) ) );

                $keys = ',';
                $strsLen = count( $strs );
                for ( $i = 0; $i < $strsLen; $i++ ) {
                    $keys .= $v[ $strs[ $i ] ] . ',';
                }
                $returnData[ $keys ] = $v;
            } else {
                $returnData[ $v[ $field ] ] = $v;
            }
        }

        return $returnData;

    }


    /**
     *根据某字段对多维数组进行排序
     * @param $array  要排序的数组
     * @param $field  要根据的数组下标
     * @return void
     */
    public static function sortArrByField( &$array, $field, $desc = false )
    {
        $fieldArr = array();
        foreach ( $array as $k => $v ) {
            $fieldArr[ $k ] = $v[ $field ];
        }
        $sort = $desc == false ? SORT_ASC : SORT_DESC;
        array_multisort( $fieldArr, $sort, $array );
    }

    /**
     * 判断字段是否存在并且不为空
     * @param $key 支持数组，字符串（"a，b"）
     * @param $array
     * @return bool
     */
    public static function keyIsExistence( $key, $array = [] )
    {
        if ( empty( $array ) ) {
            return false;
        }
        if ( !is_array( $key ) ) {
            $key = explode( ",", $key );
        }

        foreach ( $key as $k => $v ) {

            if ( array_key_exists( $v, $array ) && !empty( $array[ $v ] ) ) {
                continue;
            } else {
                return false;
            }
        }

        return true;
    }

    /**
     * 用户名、邮箱、手机账号中间字符串以*隐藏
     * @param string $str
     * @return null|string|string[]
     */
    public static function replaceStar( $str = '' )
    {
        if ( empty( $str ) ) return $str;

        if ( strpos( $str, '@' ) ) {
            $email_array = explode( "@", $str );
            $prevfix = ( strlen( $email_array[0] ) < 4 ) ? "" : substr( $str, 0, 3 ); //邮箱前缀
            $count = 0;
            $str = preg_replace( '/([\d\w+_-]{0,100})@/', '***@', $str, -1, $count );
            $rs = $prevfix . $str;
        } else {
            $pattern = "/^1[3456789]\d{9}$/";
            if ( preg_match( $pattern, $str ) ) {

                $rs = substr_replace( $str, '****', 3, 4 );
            } else {
                $rs = substr( $str, 0, 3 ) . "***" . substr( $str, -1 );
            }
        }
        return $rs;
    }

    /**
     * 随机生成字符串
     * @param $field
     * @param $model
     * @param int $length
     * @return string
     */
    public static function nonceStr( $length = 32 )
    {
        $chars = 'abcdefghijkmnprstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
        $str = '';
        for ( $i = 0; $i < $length; $i++ ) {
            $str .= substr( $chars, mt_rand( 0, strlen( $chars ) - 1 ), 1 );
        }
        return $str;
    }

    /**
     * 随机生成唯一字符串
     * @param $field
     * @param $model
     * @param int $length
     * @type int  1:字符串 2:数字
     * @return string
     */
    public static function nonceStrByUnique( $field, $model, $tableName, $length = 6, $type = 1 )
    {
        $chars = $type == 1 ? 'abcdefghijkmnprstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' : '0123456789';
        $str = '';
        do {

            for ( $i = 0; $i < $length; $i++ ) {
                $str .= substr( $chars, mt_rand( 0, strlen( $chars ) - 1 ), 1 );
            }

        } while ( $model->where( $field, $str )->has( $tableName ) );

        return $str;
    }

    /**
     * 获取唯一订单号
     * @param $field
     * @param $model
     * @return string
     */
    public static function ordeSnByUnique( $field, $model, $tableName )
    {
        $str = "";
        $yCode = array('A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z');

        do {
            $str = (String)$yCode[ intval( date( 'Y' ) ) - 2011 ] . strtoupper( dechex( date( 'm' ) ) ) . date( 'd' ) . time() . substr( microtime(), 2, 5 ) . sprintf( '%02d', rand( 0, 99 ) );
        } while ( $model->where( $field, $str )->has( $tableName ) );

        return $str;

    }

    /**
     * 判断身份證格式
     * @param $idcard
     * @return bool
     */
    public static function bankCardRule( $id )
    {
        $id = strtoupper( $id );
        $regx = "/(^\d{15}$)|(^\d{17}([0-9]|X)$)/";
        $arr_split = array();
        if ( !preg_match( $regx, $id ) ) {
            return FALSE;
        }
        if ( 15 == strlen( $id ) ) //检查15位
        {
            $regx = "/^(\d{6})+(\d{2})+(\d{2})+(\d{2})+(\d{3})$/";

            @preg_match( $regx, $id, $arr_split );
            //检查生日日期是否正确
            $dtm_birth = "19" . $arr_split[2] . '/' . $arr_split[3] . '/' . $arr_split[4];
            if ( !strtotime( $dtm_birth ) ) {
                return FALSE;
            } else {
                return TRUE;
            }
        } else      //检查18位
        {
            $regx = "/^(\d{6})+(\d{4})+(\d{2})+(\d{2})+(\d{3})([0-9]|X)$/";
            @preg_match( $regx, $id, $arr_split );
            $dtm_birth = $arr_split[2] . '/' . $arr_split[3] . '/' . $arr_split[4];
            if ( !strtotime( $dtm_birth ) ) //检查生日日期是否正确
            {
                return FALSE;
            } else {
                //检验18位身份证的校验码是否正确。
                //校验位按照ISO 7064:1983.MOD 11-2的规定生成，X可以认为是数字10。
                $arr_int = array(7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2);
                $arr_ch = array('1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2');
                $sign = 0;
                for ( $i = 0; $i < 17; $i++ ) {
                    $b = (int)$id{$i};
                    $w = $arr_int[ $i ];
                    $sign += $b * $w;
                }
                $n = $sign % 11;
                $val_num = $arr_ch[ $n ];
                if ( $val_num != substr( $id, 17, 1 ) ) {
                    return FALSE;
                } //phpfensi.com
                else {
                    return TRUE;
                }
            }
        }

    }

    /**
     * 时间格式转换
     * @param $time
     * @param int $type
     * @return false|string
     */
    public static function dateFormat( $time, $type = 1 )
    {
        $time = is_numeric( $time ) ? $time : strtotime( $time );

        switch ( $type ) {
            case 1:
                $format = 'Y-m-d H:i:s';
                break;
            case 2:
                $format = 'Y.m.d H:i:s';
                break;
            case 3:
                $format = 'Y-m-d';
                break;
            default:
                $format = 'Y-m-d H:i:s';
                break;
        }

        return date( $format, $time );
    }

    /**
     * 对象处理为数组
     * @param array $array
     * @return mixed
     */
    public static function toArray( $array = [] )
    {
        return json_decode( json_encode( $array ), true );
    }

    /**
     *分割二维数组为三维数组
     * @param $data
     * @param int $count
     * @return array
     */
    public static function divisionData( $data, $count = 5000 )
    {
        $returnData = [];
        #分割数据--每组5000批量添加
        $num = count( $data );
        $j = (int)ceil( $num / $count );
        $start = 0;
        for ( $i = 1; $i <= $j; $i++ ) {
            $shuliang = (int)ceil( ( $num - $start ) / ( $j - $i + 1 ) );
            $returnData[ $i - 1 ] = array_slice( $data, $start, $shuliang );
            $start += $shuliang;
        }

        return $returnData;
    }

    /**
     * [i_array_column 提取数组中的某一列数据等同array_column,解决php版本中无此函数的问题]
     * @param  [type] $input     [description]
     * @param  [type] $columnKey [description]
     * @param  [type] $indexKey  [description]
     * @return [type]            [description]
     */
    public static function i_array_column( $input, $columnKey, $indexKey = null )
    {
        if ( !function_exists( 'array_column' ) ) {
            $columnKeyIsNumber = ( is_numeric( $columnKey ) ) ? true : false;
            $indexKeyIsNull = ( is_null( $indexKey ) ) ? true : false;
            $indexKeyIsNumber = ( is_numeric( $indexKey ) ) ? true : false;
            $result = array();
            foreach ( (array)$input as $key => $row ) {
                if ( $columnKeyIsNumber ) {
                    $tmp = array_slice( $row, $columnKey, 1 );
                    $tmp = ( is_array( $tmp ) && !empty( $tmp ) ) ? current( $tmp ) : null;
                } else {
                    $tmp = isset( $row[ $columnKey ] ) ? $row[ $columnKey ] : null;
                }
                if ( !$indexKeyIsNull ) {
                    if ( $indexKeyIsNumber ) {
                        $key = array_slice( $row, $indexKey, 1 );
                        $key = ( is_array( $key ) && !empty( $key ) ) ? current( $key ) : null;
                        $key = is_null( $key ) ? 0 : $key;
                    } else {
                        $key = isset( $row[ $indexKey ] ) ? $row[ $indexKey ] : 0;
                    }
                }
                $result[ $key ] = $tmp;
            }
            return $result;
        } else {
            return array_column( $input, $columnKey, $indexKey );
        }
    }

    //请确保项目文件有可写权限，不然打印不了日志。
    public static function writeLog( $text, $message = '', $name = "log.txt" )
    {
        // $text=iconv("GBK", "UTF-8//IGNORE", $text);
        //$text = characet ( $text );
        file_put_contents( $name, date( "Y-m-d H:i:s" ) . "  " . $text . '-----' . $message . "\r\n", FILE_APPEND );
    }

    public static function checkIdCard( $id )
    {
        $id = strtoupper( $id );
        $regx = "/(^\d{15}$)|(^\d{17}([0-9]|X)$)/";
        $arr_split = array();
        if ( !preg_match( $regx, $id ) ) {
            return FALSE;
        }
        if ( 15 == strlen( $id ) ) //检查15位
        {
            $regx = "/^(\d{6})+(\d{2})+(\d{2})+(\d{2})+(\d{3})$/";

            @preg_match( $regx, $id, $arr_split );
            //检查生日日期是否正确
            $dtm_birth = "19" . $arr_split[2] . '/' . $arr_split[3] . '/' . $arr_split[4];
            if ( !strtotime( $dtm_birth ) ) {
                return FALSE;
            } else {
                return TRUE;
            }
        } else      //检查18位
        {
            $regx = "/^(\d{6})+(\d{4})+(\d{2})+(\d{2})+(\d{3})([0-9]|X)$/";
            @preg_match( $regx, $id, $arr_split );
            $dtm_birth = $arr_split[2] . '/' . $arr_split[3] . '/' . $arr_split[4];
            if ( !strtotime( $dtm_birth ) ) //检查生日日期是否正确
            {
                return FALSE;
            } else {
                //检验18位身份证的校验码是否正确。
                //校验位按照ISO 7064:1983.MOD 11-2的规定生成，X可以认为是数字10。
                $arr_int = array(7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2);
                $arr_ch = array('1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2');
                $sign = 0;
                for ( $i = 0; $i < 17; $i++ ) {
                    $b = (int)$id{$i};
                    $w = $arr_int[ $i ];
                    $sign += $b * $w;
                }
                $n = $sign % 11;
                $val_num = $arr_ch[ $n ];
                if ( $val_num != substr( $id, 17, 1 ) ) {
                    return FALSE;
                } else {
                    return TRUE;
                }
            }
        }


    }


}
